dev-server与HMR提高开发效率
前言 在上一篇博客中,我们配置好了最基础的功能,它能处理js、css、html基础的文件,并且能够分区域打包,形成一个较为规范的dist目录,当然,仅仅实现这些功能是不够的,我们这章节主要来介绍以下如何更方便我们开发调试。
why dev-server 我们在之前的配置中,每次修改js或者css后,都需要build一次才能看到新的页面,这当然是不可取的,如果你用过create-react-app 或者 vue-cli生成的项目,你就会在知道package.json中有一个script启动脚本npm run dev,这就能让我们边改代码,边调试,效率非常高。
具体配置 分清dev与prod环境 我们在设置package.json的script脚本时,会带上环境设置:
1 2 3 4 5 "scripts" : { "test" : "echo \"Error: no test specified\" && exit 1" , "build" : "webpack --mode production" , "dev" : "webpack-dev-server --mode development" },
为什么要这么设置呢,因为在webpack配置当中,我们要区分开dev和prod环境,来做不同的处理,比如我们之前使用到的mini-css-extract-plugin,他在prod环境下是能够很方便的将css分离出来,但是如果在dev环境下使用HMR(热更新),这个时候mini-css-extract-plugin就会和HMR有冲突,因为mini-css-extract-plugin并不支持HMR,所以,我们在配置HMR之前,先设置好在dev中不使用mini-css-extract-plugin,用style-loader替代便能完美地进行热更新啦~
切换css的loader 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const MiniCssExtractPlugin = require ("mini-css-extract-plugin" );module .exports = (env, argv ) => { const devMode = argv.mode === 'development' return { ... plugins: [ ... new MiniCssExtractPlugin({ filename: "css/[name].[hash].css" , chunkFilename: "css/[id].[hash].css" , }) ], module : { rules: [ { test: /\.css/ , use: [ devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader' ] } ] } } }
这里,我们设置了一个变量devMode,它表示是否处于development的环境下,如果是,则使用style-loader,这样在dev环境下便不会和HMR冲突,如果是在prod环境下,则使用MiniCssExtractPlugin.loader来分离出css
引入webpack-dev-server 在使用之前,我们先npm i webpack-dev-server -D,安装完成后,我们在webpack.config.js中配置devServer选项:
1 2 3 4 5 6 7 8 9 10 11 module .exports = (env, argv ) => { const devMode = argv.mode === 'development' return { ... devServer: { compress: true , port: 9000 , open: true } } }
compress 表示服务是否启动Gzip压缩,这里我们开启以加快加载速度
port 表示服务启动的端口号,注意开发的时候不要被其他的服务占用了,最好设置一个少见的端口号
open 表示是否自动打开网页
配置完成之后,启动dev:run dev```,便会自动开启一个9000端口的网页,当你改动css或者js的时候,网页会自动刷新,这样一个dev环境就初步搭建好了,但是你会发现,当你改变js的时候,整个页面都全部刷新了,控制台中的console也全部没了,这对我们开发其实并不是特别友好的,我们希望改动代码后,能够实时看到更新结果,并且页面不要自动刷新,这对我们开发是非常有帮助的,比如一些需要点击打开的弹窗,当你改变其样式后,页面自动刷新,这时候你又要手动打开这个弹窗,来查看更新结果,这显然是不优雅的,于是我们开始下一步:HMR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ### 启动HMR 启动HMR其实并不是非常复杂的行为,但是又一个坑困扰我许久,在最后我将会指出,我们继续更改webpack配置: 修改devServer选项,添加hot属性; ``` javascript module.exports = (env, argv) => { const devMode = argv.mode === 'development' return { ... devServer: { compress: true, port: 9000, hot: true, open: true } } }
增加HMR的插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const webpack = require ('webpack' )module .exports = (env, argv ) => { const devMode = argv.mode === 'development' return { entry: './src/index.js' , output: { ... }, plugins: [ new webpack.HotModuleReplacementPlugin(), ], module : { ... }, devServer: { compress: true , port: 9000 , hot: true , open: true } } }
这样,我们似乎就已经配置完毕了,但是当我们运行dev命令后,更改css后,页面不刷新便能看到更新结果,但是更改js文件后,还是会刷新页面,当初非常疑惑,之后后面谷歌才发现,需要在入口文件加入一段js代码:
1 2 3 4 5 6 7 ... if (module .hot) { module .hot.accept(); }
这是webpack的HMR对js文件的特殊处理,我们再次修改js文件时,发现已经不再需要刷新页面,便能实时查看更新结果。
last 最后,我们来看完整的webpack.config.js配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 const path = require ('path' )const webpack = require ('webpack' )const HtmlWebpackPlugin = require ('html-webpack-plugin' )const MiniCssExtractPlugin = require ("mini-css-extract-plugin" );module .exports = (env, argv ) => { const devMode = argv.mode === 'development' return { entry: './src/index.js' , output: { path: path.resolve(__dirname, 'dist' ), filename: 'js/bundle.js' }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' , filename: 'index.html' }), new MiniCssExtractPlugin({ filename: "css/[name].[hash].css" , chunkFilename: "css/[id].[hash].css" , }), new webpack.HotModuleReplacementPlugin(), ], module : { rules: [ { test: /\.css/ , use: [ devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader' ] }, { test: /\.(png|jpg|gif|jpeg|svg)$/ , use: [ { loader: 'url-loader' , options: { limit: 1024 , name: '[name].[hash:6].[ext]' , outputPath: 'images/' , publicPath: '../images' } } ] } ] }, devServer: { compress: true , port: 9000 , hot: true , open: true } } }
通过我们的倒腾,这下总算是有了真正开发的模样,dev-server提高了我们开发效率,配合HMR,我们能够实现一些很方便的调试,当然,距离配置出完美地工程还有很远,请关注我的博客后续更新~
本章节的代码已经上传到Github,传送门webpack-study ,请自行切换到chapter-02分支。
In doing we learn. :)